package com.lagou.edu.scanner.impl;

import com.lagou.edu.scanner.ClassScanner;
import com.lagou.edu.scanner.Matcher;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;


public class ClassScannerImpl implements ClassScanner {
    /**
     * 根据传入的路径，经过匹配器进行扫描，返回满足要求的类
     * @param path 路径
     * @param matcher 匹配器
     * @return 满足要求的类
     */
    @Override
    public List<Class<?>> scanner(String path, Matcher matcher) {
        List<Class<?>> classList = new ArrayList<>();
        try {
            //将给定的路径转换成包的路径
            File packagePath = resolvePackagePath(path);
            scanPackagePath(packagePath, matcher, classList);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return classList;
    }

    /**
     * 将路径转换成包的路径
     * @param path 路径
     * @return 包的路径
     * @throws URISyntaxException
     */
    private File resolvePackagePath(String path) throws URISyntaxException {
        URL rootPath = getClass().getResource("/");
        File rootDir = new File(rootPath.toURI());
        return new File(rootDir, path.replace("\\.", "/"));
    }

    /**
     * 扫描包路径
     * @param packagePath 包路径
     * @param matcher 匹配器
     * @param classList 存放匹配的类的列表
     * @throws IOException
     * @throws URISyntaxException
     * @throws ClassNotFoundException
     */
    private void scanPackagePath(File packagePath, Matcher matcher, List<Class<?>> classList) throws IOException, URISyntaxException, ClassNotFoundException {
        //循环遍历包路径，依次递归调用扫描方法
        if (packagePath.isDirectory()){
            File[] files = packagePath.listFiles();
            for (File file : files){
                scanPackagePath(file, matcher, classList);
            }
            return;
        }
        //判断是否为类文件
        String canonicalPath = packagePath.getCanonicalPath();
        if (!canonicalPath.endsWith(".class")) {
            return;
        }
        //判断类是否匹配
        Class<?> clz = loadClass(canonicalPath);
        if (!matcher.isMatch(clz)) {
            return;
        }
        classList.add(clz);
    }

    /**
     * 加载类文件
     * @param classFile 给定的类文件
     * @return 类对象
     */
    private Class<?> loadClass(String classFile) throws ClassNotFoundException, URISyntaxException, IOException {
        URL rootPath = getClass().getResource("/");
        File rootDir = new File(rootPath.toURI());

        String classPath = classFile.replace(rootDir.getCanonicalPath(), "")
                .replaceAll("\\\\|/", ".");
        if (classPath.startsWith(".")) {
            classPath = classPath.substring(1);
        }

        int idx = classPath.lastIndexOf(".class");
        String className = classPath.substring(0, idx);

        return Class.forName(className);
    }
}
